//
//  BVideoCacheTool.m
//  Bullet
//
//  Created by  on 2019/9/17.
//  Copyright © 2019 . All rights reserved.
//

#import "BVideoCacheTool.h"
#import <AVFoundation/AVFoundation.h>
#import "BFileDownloaderTool.h"
#import "BFileManagerTool.h"
#import "BCacheMapTool.h"
#import "GCDWebDAVServer.h"
#import "BM3U8LocalFileParser.h"

static GCDWebDAVServer *DavServer = nil;
@interface BVideoCacheTool()<GCDWebDAVServerDelegate,BFileDownloaderToolDelegate>
//{
//    GCDWebDAVServer *_davServer;
//}

@property (nonatomic,strong) NSOperationQueue *cacheQueue;
@property (nonatomic,strong) NSMutableArray *tsLoadA;
@property (nonatomic,strong) NSMutableArray *finishedTsLoadA;
@property (nonatomic,assign) BOOL hasDownloadKeyFile;
@property (nonatomic,copy) NSString *keyFileName;
@property (nonatomic,strong) BFileDownloaderTool *lastDownloader;
@property (nonatomic,assign) NSInteger preloadingMaxCount;

@property (nonatomic,strong) NSMutableArray<BFileDownloaderTool *> *downloadingA;

@property (nonatomic,copy) NSString *lastFinishedUrl;

@property (nonatomic,copy) void(^resultHandler)(NSString *filePath,BOOL isLocalCache);

@end

@implementation BVideoCacheTool

- (NSMutableArray<BFileDownloaderTool *> *)downloadingA{
    if(!_downloadingA){
        _downloadingA = [NSMutableArray array];
    }
    return _downloadingA;
}

- (NSMutableArray *)finishedTsLoadA{
    if(!_finishedTsLoadA){
        _finishedTsLoadA = [NSMutableArray array];
    }
    return _finishedTsLoadA;
}

- (NSMutableArray *)tsLoadA{
    if(!_tsLoadA){
        _tsLoadA = [NSMutableArray array];
    }
    return _tsLoadA;
}

- (NSOperationQueue *)cacheQueue{
    if(!_cacheQueue){
        _cacheQueue = [[NSOperationQueue alloc] init];
    }
    return _cacheQueue;
}

- (void)initiailWithMaxCacheCount:(NSInteger)maxCacheCount preloadingMaxCount:(NSInteger)preloadingMaxCount{
    self.preloadingMaxCount = preloadingMaxCount;
    DavServer = [[GCDWebDAVServer alloc] initWithUploadDirectory:[[BFileManagerTool tool] fileSaveCachePath]];
    DavServer.delegate = self;
    [DavServer start];
//    BLog(@"Visit %@ in your WebDAV client，name is %@", DavServer.serverURL,DavServer.bonjourName);
    [BCacheMapTool tool].maxMapLength = maxCacheCount;
    [[BCacheMapTool tool] clearAllLoadingCacheAndFolder];
}

- (BVideoCacheResult)getVideoPathWithWebUrl:(NSString *)urlStr{
    return [self getVideoPathWithWebUrl:urlStr preLoad:NO];
}

- (BVideoCacheResult)getVideoPathWithWebUrl:(NSString *)urlStr preLoad:(BOOL)preload{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if([fileManager fileExistsAtPath:urlStr] && ![urlStr containsString:@".m3u8"]){
        return BVideoCacheResultMake(urlStr, YES, -1.f);
    }
    NSString *cachePath = [[BFileManagerTool tool] videoCachePathForUrl:urlStr preload:preload];
    if([[BCacheMapTool tool] localFileIsExist:urlStr preload:preload]){
        if([cachePath containsString:@".m3u8"]){

            NSString *cachePath22 = [[BFileManagerTool tool] videoCachePathForUrl:urlStr preload:NO];
            BM3U8LocalFileParser *totalTimeParser = [[BM3U8LocalFileParser alloc] initWithLocalPath:cachePath22];
#if TARGET_IPHONE_SIMULATOR
            NSString *localBaseUrl = @"http://127.0.0.1:8080";
#else
            NSString *localBaseUrl = @"http://127.0.0.1:80";
#endif
            if(!DavServer.isRunning){
                DavServer = [[GCDWebDAVServer alloc] initWithUploadDirectory:[[BFileManagerTool tool] fileSaveCachePath]];
                DavServer.delegate = self;
                [DavServer start];
//                BLog(@"restart local web server.");
            }
            
            if(!IS_NULL_STR([DavServer serverURL].absoluteString) ){
                localBaseUrl = [DavServer serverURL].absoluteString;
                if([localBaseUrl hasSuffix:@"/"]){
                    localBaseUrl = [localBaseUrl substringToIndex:localBaseUrl.length - 1];
                }
            }

            NSString *appendUrl = [cachePath stringByReplacingOccurrencesOfString:[[BFileManagerTool tool] fileSaveCachePath] withString:@""];
            NSString *realUrl = [localBaseUrl stringByAppendingString:appendUrl];
            
//            BLog(@"*******************get local cache video path url is %@",realUrl);
            return BVideoCacheResultMake(realUrl, NO,totalTimeParser.totalDuration);
        }
        else
        {
//            BLog(@"*******************get local cache video path url is %@",cachePath);
            return BVideoCacheResultMake(cachePath, YES,-1.f);
        }
    }
//    BLog(@"*******************get web video path url is %@",urlStr);
    [self preloadLoadVideo:urlStr preLoad:preload];
    return BVideoCacheResultMake(urlStr, NO,-1.f);
}

- (void)preloadLoadVideo:(NSString *)urlStr{
    [self preloadLoadVideo:urlStr preLoad:NO];
}

- (void)preloadLoadVideo:(NSString *)urlStr preLoad:(BOOL)preload{
     if([[BCacheMapTool tool] localFileIsExist:urlStr preload:preload]){
         return;
     }
    @try {
        
        NSPredicate *currentPredicate = [NSPredicate predicateWithFormat:@"urlStr == %@",urlStr];
        
        NSArray *thisDowns = [self.downloadingA filteredArrayUsingPredicate:currentPredicate];
        if(thisDowns.count > 0){
            BOOL hasRemove = NO;
            for (BFileDownloaderTool *downloaderTool in thisDowns) {
                if(downloaderTool.status != BFileDownloaderStatusDownlodding){
                    hasRemove = YES;
                    [downloaderTool stopAndClean];
                    [self.downloadingA removeObject:downloaderTool];
                }
            }
            if(!hasRemove){
                return;
            }
        }
        if(self.downloadingA.count >= self.preloadingMaxCount){
            BFileDownloaderTool *downloader = self.downloadingA.firstObject;
            if(![downloader.urlStr isEqualToString:urlStr]){
                [downloader stopAndClean];
                [self.downloadingA removeObject:downloader];
            }
            else
            {
                return;
            }
        }
        BFileDownloaderTool *downloader = [[BFileDownloaderTool alloc] initWithUrl:urlStr baseUrl:urlStr type:3 target:self queue:self.cacheQueue preload:preload];
        downloader.parentObj = self;
        
        [downloader startDownload];
        [self.downloadingA addObject:downloader];
    } @catch (NSException *exception) {
//        BLog(@"preload file error,%@",exception);
    } @finally {
        
    }
    
    
}

#pragma mark - BFileDownloaderDelegate

- (void)fileDownloader:(BFileDownloaderTool *)fileDownLoader didFinishedWithFilePath:(NSString *)filePath isCacheLocal:(BOOL)isCacheLocal{
    __block typeof(self) tmpSelf = self;
    self.lastFinishedUrl = fileDownLoader.urlStr;
//    BLog(@"..............3...fileDownLoader is url is %@",fileDownLoader.urlStr);
//    BLog(@"has loading finished %@",fileDownLoader.urlStr);
    if([self.downloadingA containsObject:fileDownLoader]){
        [self.downloadingA removeObject:fileDownLoader];
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        if(tmpSelf.resultHandler){
            tmpSelf.resultHandler(filePath, isCacheLocal);
        }
    });
}

#pragma mark - file manager

- (void)deleteVideoCache{
    for (BFileDownloaderTool *downloader in self.downloadingA) {
        [downloader stopAndClean];
    }
    [self.downloadingA removeAllObjects];
    [[BFileManagerTool tool] deleteVideoCacheFolder:^{
        [[BCacheMapTool tool] clearMap];
    }];
}

- (void)deleteAllUserCache{
    
    for (BFileDownloaderTool *downloader in self.downloadingA) {
        [downloader stopAndClean];
    }
    [self.downloadingA removeAllObjects];
    [[BFileManagerTool tool] clearAllCache:^{
        [[BCacheMapTool tool] clearMap];
    }];
}

- (NSString *)userCacheSize{
    long long size = [[BFileManagerTool tool] userCacheSize];
    return [NSString memerySizeStrWithSize:size];
}

#pragma mark - 

+ (instancetype)tool{
    static BVideoCacheTool *tool = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        tool = [[BVideoCacheTool alloc] init];
    });
    return tool;
}

@end
